package com.luoyx.vjsb.authority.security.handler;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.luoyx.vjsb.authority.security.SecurityUserDetails;
import com.luoyx.vjsb.authority.security.constant.SecurityConstant;
import com.luoyx.vjsb.authority.security.properties.TokenProperties;
import com.luoyx.vjsb.authority.vo.TokenUser;
import com.luoyx.vjsb.common.annotation.Logs;
import com.luoyx.vjsb.common.util.AjaxResult;
import com.luoyx.vjsb.common.util.AuthUtil;
import com.luoyx.vjsb.common.util.IpInfoUtil;
import com.luoyx.vjsb.core.entity.SysUser;
import com.luoyx.vjsb.core.service.ISysUserService;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 登录成功处理类
 * </p>
 *
 * @author luoyuanxiang
 * @date 2020/5/4 16:27
 */
@Slf4j
@Component
public class AuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private TokenProperties tokenProperties;

    @Resource
    private IpInfoUtil ipInfoUtil;

    @Resource
    private ISysUserService iSysUserService;

    @Resource
    private AuthUtil authUtil;

    @Override
    @Logs("登录系统")
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
        // 用户选择保存登录状态几天（记住我）
        String saveLogin = request.getParameter(SecurityConstant.SAVE_LOGIN);
        boolean saved = false;
        if(StrUtil.isNotBlank(saveLogin) && Boolean.parseBoolean(saveLogin)){
            saved = true;
            if(!tokenProperties.getRedis()){
                tokenProperties.setTokenExpireTime(tokenProperties.getSaveLoginTime() * 60 * 24);
            }
        }
        SecurityUserDetails securityUserDetails =  (SecurityUserDetails)authentication.getPrincipal();
        String username = securityUserDetails.getUser().getUsername();
        List<GrantedAuthority> authorities = (List<GrantedAuthority>) ((UserDetails)authentication.getPrincipal()).getAuthorities();
        List<String> list = new ArrayList<>();
        for(GrantedAuthority g : authorities){
            list.add(g.getAuthority());
        }
        ipInfoUtil.getUrl(request);
        // 登陆成功生成token
        String token;
        if(tokenProperties.getRedis()){
            // redis
            token = UUID.randomUUID().toString().replace("-", "");
            TokenUser user = new TokenUser(username, list, saved);
            // 不缓存权限
            if(!tokenProperties.getStorePerms()){
                user.setPermissions(null);
            }
            // 单设备登录 之前的token失效
            if(tokenProperties.getSdl()){
                String oldToken = stringRedisTemplate.opsForValue().get(SecurityConstant.USER_TOKEN + username);
                if(StrUtil.isNotBlank(oldToken)){
                    stringRedisTemplate.delete(SecurityConstant.TOKEN_PRE + oldToken);
                }
            }
            if(saved){
                stringRedisTemplate.opsForValue().set(SecurityConstant.USER_TOKEN + username, token, tokenProperties.getSaveLoginTime(), TimeUnit.DAYS);
                stringRedisTemplate.opsForValue().set(SecurityConstant.TOKEN_PRE + token, JSONUtil.toJsonStr(user), tokenProperties.getSaveLoginTime(), TimeUnit.DAYS);
            }else{
                stringRedisTemplate.opsForValue().set(SecurityConstant.USER_TOKEN + username, token, tokenProperties.getTokenExpireTime(), TimeUnit.MINUTES);
                stringRedisTemplate.opsForValue().set(SecurityConstant.TOKEN_PRE + token, JSONUtil.toJsonStr(user), tokenProperties.getTokenExpireTime(), TimeUnit.MINUTES);
            }
        }else{
            // JWT不缓存权限 避免JWT长度过长
            // JWT
            token = SecurityConstant.TOKEN_SPLIT + Jwts.builder()
                //主题 放入用户名
                .setSubject(username)
                //自定义属性 放入用户拥有请求权限
                .claim(SecurityConstant.AUTHORITIES, JSONUtil.toJsonStr(list))
                //失效时间
                .setExpiration(new Date(System.currentTimeMillis() + tokenProperties.getTokenExpireTime() * 60 * 1000))
                //签名算法和密钥
                .signWith(SignatureAlgorithm.HS512, SecurityConstant.JWT_SIGN_KEY)
                .compact();
        }
        SysUser user = securityUserDetails.getUser();
        user.setLoginCount(securityUserDetails.getUser().getLoginCount() + 1);
        authUtil.setUsername(username);
        iSysUserService.updateById(user);
        AjaxResult.out(response, AjaxResult.success(token, "登录成功"));
    }
}
